import java.util.LinkedList;
import java.util.ListIterator;
import java.io.*;
/**
 * Klasa realizuje optymalizacje funkcji 
 * metoda algorytmu genetycznego
 * @author pawel
 *
 */
public class algorithm {
	/*
	 * Maksymalna ilosc pokolen
	 */
	private long generations;
	private przedzial range;
	private double mutationProbability;
	private populacja population; 
	/*
	 * Zapisuje historie populacji
	 */
	public LinkedList<populationSnapshot> popSnapshots;
/**
 * Tworzy instancje 	
 * @param from	poczatek przedzialu
 * @param to	koniec przedzialu
 * @param mutationProbability	prawdopodobienstwo mutacji osobnika
 * @param generations			maksymalna ilosc pokolen
 * @param initialPopulation		populacja poczatkowa
 */
	algorithm(double from, double to, double mutationProbability,long generations,double[] initialPopulation){
		this.generations = generations;
		this.range = new przedzial(from,to);
		this.mutationProbability = mutationProbability;
		this.population = new populacja(initialPopulation, this.range);
		this.popSnapshots = new LinkedList<populationSnapshot>();
		
	}
	/**
	 * Tworzy instancje z losowa populacja  	
	 * @param from	poczatek przedzialu
	 * @param to	koniec przedzialu
	 * @param mutationProbability	prawdopodobienstwo mutacji osobnika
	 * @param generations			maksymalna ilosc pokolen
	 * @param initialPopulation		populacja poczatkowa
	 */	
	algorithm(double from, double to, double mutationProbability,long generations,int initPopulationSize){
		this.generations = generations;
		this.range = new przedzial(from,to);
		this.mutationProbability = mutationProbability;
		this.population = new populacja(initPopulationSize, this.range);
		this.popSnapshots = new LinkedList<populationSnapshot>();
	}
/**
 * Uruchamia algorytm	
 */
	public  osobnik run(){
		long generationCounter = 0;
		osobnik best,tmp;
		population.evaluate();
		this.popSnapshots.push(new populationSnapshot(this.population, generationCounter));
		this.population.evaluate();
		best = new osobnik(population.getBest());
		while(generationCounter < this.generations){
		
			this.population.recombination();
			
			
			this.population.mutateWithProbability(this.mutationProbability);
			
			this.population.evaluate();
			
			System.out.println(this.population);
			
			this.population.selection();

			this.population.evaluate();
			this.popSnapshots.push(new populationSnapshot(this.population, generationCounter));
			tmp = this.population.getBest();
			if(tmp.getFunctionValue() < best.getFunctionValue()){
				best = new osobnik(tmp);
			}
			
			//System.out.println(this.population);
			generationCounter++;
			
		}
		return best;
	}
/**
 * Tworzy plik csv ze snashotow populacji
 * Uzywam tego do szybkiego generowania wykresu
 * Glownie cele testowe
 * @param outFile plik docelowy
 */
	public void printCSVLog(String outFile){
		ListIterator<populationSnapshot> iter = this.popSnapshots.listIterator();
		populationSnapshot tmpSnap;
		try {
			BufferedWriter out = new BufferedWriter(new FileWriter(outFile));
			while(iter.hasNext()){
				tmpSnap = iter.next();
				out.write(Long.toString(tmpSnap.getGeneration()) + ";" + Double.toString(tmpSnap.getAverage())+";"
						+Double.toString(tmpSnap.getBest().getFunctionValue()) + "\n");
			}
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
public populacja getPopulation() {
	return population;
}
public void setPopulation(populacja population) {
	this.population = population;
}
	

}
